import json
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

from ..models.data_source import SourceType
from ..utils.logger import logger
from .field_dialog import FieldDialog


class FieldManager:
    """字段管理功能"""

    def _create_fields_frame(self, parent):
        """创建字段管理区域"""
        fields_frame = ttk.LabelFrame(parent, text="数据项维护")
        fields_frame.pack(fill=tk.X, padx=10, pady=5)

        # 创建表格和按钮
        self._create_fields_tree(fields_frame)
        self._create_fields_buttons(fields_frame)

        return fields_frame

    def _create_fields_tree(self, parent):
        """创建字段列表树形控件"""
        # 创建表格和按钮的容器
        list_frame = ttk.Frame(parent)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 创建数据项表格，修改列的顺序
        columns = ("is_id", "name", "code", "description")  # 将 is_id 移到第一位
        self.fields_tree = ttk.Treeview(
            list_frame, columns=columns, show="headings", height=5
        )

        # 设置列标题
        self.fields_tree.heading("is_id", text="主键", anchor="center")
        self.fields_tree.heading("name", text="字段名称", anchor="center")
        self.fields_tree.heading("code", text="字段代码", anchor="center")
        self.fields_tree.heading("description", text="字段描述", anchor="center")

        # 设置列宽
        self.fields_tree.column("is_id", width=80, anchor="center")
        self.fields_tree.column("name", width=150, anchor="center")
        self.fields_tree.column("code", width=150, anchor="center")
        self.fields_tree.column("description", width=200, anchor="center")

        # 添加滚动条
        scrollbar = ttk.Scrollbar(
            list_frame, orient=tk.VERTICAL, command=self.fields_tree.yview
        )
        self.fields_tree.configure(yscrollcommand=scrollbar.set)

        # 放置表格和滚动条
        self.fields_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    def _create_fields_buttons(self, parent):
        """创建字段操作按钮"""
        # 按钮区域
        btn_frame = ttk.Frame(parent)
        btn_frame.pack(fill=tk.X, padx=5, pady=5)

        # 左侧操作按钮
        left_btn_frame = ttk.Frame(btn_frame)
        left_btn_frame.pack(side=tk.LEFT)

        ttk.Button(left_btn_frame, text="添加", command=self._on_add_field).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(left_btn_frame, text="编辑", command=self._on_edit_field).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(left_btn_frame, text="删除", command=self._on_delete_field).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(
            left_btn_frame, text="设为ID字段", command=self._on_toggle_id_field
        ).pack(side=tk.LEFT, padx=5)

        # 右侧导入导出按钮
        right_btn_frame = ttk.Frame(btn_frame)
        right_btn_frame.pack(side=tk.RIGHT)

        ttk.Button(right_btn_frame, text="导入", command=self._on_import_fields).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(right_btn_frame, text="导出", command=self._on_export_scheme).pack(
            side=tk.LEFT, padx=5
        )

    def _refresh_fields_list(self):
        """刷新字段列表"""
        # 清空现有数据
        for item in self.fields_tree.get_children():
            self.fields_tree.delete(item)

        # 添加数据项，调整值的顺序以匹配新的列顺序
        for field in self.data_fields:
            values = [
                "✓" if field["code"] in self.id_fields else "",  # is_id 移到第一位
                field["name"],
                field["code"],
                field.get("description", ""),
            ]
            self.fields_tree.insert("", tk.END, values=values)

    def _on_add_field(self):
        """添加字段"""
        dialog = FieldDialog(self.window)
        self.window.wait_window(dialog)
        if dialog.result:
            self.data_fields.append(dialog.result)
            self._refresh_fields_list()

    def _on_edit_field(self):
        """编辑字段"""
        selection = self.fields_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个字段")
            return

        item = selection[0]
        values = self.fields_tree.item(item)["values"]
        old_code = values[1]  # 获取原字段代码

        # 打开编辑对话框
        dialog = FieldDialog(self.window, values[0], old_code, values[2])
        self.window.wait_window(dialog)

        if dialog.result:
            name, new_code, description = dialog.result

            # 更新数据项
            for field in self.data_fields:
                if field["code"] == old_code:
                    field["name"] = name
                    field["code"] = new_code
                    field["description"] = description
                    break

            # 更新ID字段列表
            if old_code in self.id_fields:
                self.id_fields.remove(old_code)
                self.id_fields.append(new_code)

            # 更新数据源的字段映射
            self._update_source_mappings_after_field_change(
                old_code=old_code, new_code=new_code
            )

            # 刷新界面
            self._refresh_fields_list()
            logger.info(f"编辑字段: {old_code} -> {new_code}")

    def _on_delete_field(self):
        """删除数据项"""
        # 获取选中的数据项
        selection = self.fields_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要删除的数据项")
            return

        # 确认删除
        if not messagebox.askyesno("确认", "确定要删除选中的数据项吗？"):
            return

        try:
            # 获取要删除的字段代码
            for item in selection:
                values = self.fields_tree.item(item)["values"]
                code = values[1]  # 字段代码在第二列

                # 检查是否为ID字段
                if code in self.id_fields:
                    self.id_fields.remove(code)

                # 从数据项列表中删除
                self.data_fields = [
                    field for field in self.data_fields if field["code"] != code
                ]

                # 从树形控件中删除
                self.fields_tree.delete(item)

                # 更新数据源的字段映射
                self._update_source_mappings_after_field_change(old_code=code)

            logger.info(f"删除数据项成功: {[item for item in selection]}")

        except Exception as e:
            logger.error(f"删除数据项失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"删除失败: {str(e)}")

    def _on_import_fields(self):
        """导入数据项"""
        try:
            file_path = filedialog.askopenfilename(
                defaultextension=".json",
                filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
                title="导入数据项",
            )
            if not file_path:
                return

            with open(file_path, "r", encoding="utf-8") as f:
                data = json.load(f)

            # 加载数据项
            self.data_fields = data.get("fields", [])
            self.id_fields = data.get("id_fields", [])

            # 加载数据源配置
            source1 = data.get("source1")
            source2 = data.get("source2")

            # 加载数据源1配置
            if source1:
                source1_frame = self._find_source_frame("数据源1")
                if source1_frame:
                    self._set_source_config(
                        source1_frame,
                        SourceType(source1["type"]),
                        source1["path"],
                        source1.get("mapping", {}),
                    )
                    # 如果是数据库类型，保存数据库配置
                    if source1["type"] == "database":
                        source1_frame.db_config = source1.get("db_config", {})

            # 加载数据源2配置
            if source2:
                source2_frame = self._find_source_frame("数据源2")
                if source2_frame:
                    self._set_source_config(
                        source2_frame,
                        SourceType(source2["type"]),
                        source2["path"],
                        source2.get("mapping", {}),
                    )
                    # 如果是数据库类型，保存数据库配置
                    if source2["type"] == "database":
                        source2_frame.db_config = source2.get("db_config", {})

            # 刷新界面
            self._refresh_fields_list()
            logger.info(f"成功导入数据项: {file_path}")
            messagebox.showinfo("成功", "数据项导入成功")

        except Exception as e:
            logger.error(f"导入数据项失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"导入失败: {str(e)}")

    def _on_export_scheme(self):
        """导出对比方案"""
        try:
            file_path = filedialog.asksaveasfilename(
                defaultextension=".json",
                filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
                title="导出对比方案",
            )
            if not file_path:
                return

            # 获取当前配置
            source1 = self._create_data_source(self._find_source_frame("数据源1"))
            source2 = self._create_data_source(self._find_source_frame("数据源2"))

            scheme = {
                "fields": self.data_fields,
                "id_fields": self.id_fields,
                "source1": {
                    "type": source1.type.value if source1 else None,
                    "path": source1.path if source1 else "",
                    "mapping": source1.field_mapping if source1 else {},
                    "db_config": (
                        source1.db_config
                        if source1 and source1.type == SourceType.DATABASE
                        else {}
                    ),
                },
                "source2": {
                    "type": source2.type.value if source2 else None,
                    "path": source2.path if source2 else "",
                    "mapping": source2.field_mapping if source2 else {},
                    "db_config": (
                        source2.db_config
                        if source2 and source2.type == SourceType.DATABASE
                        else {}
                    ),
                },
            }

            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(scheme, f, ensure_ascii=False, indent=2)

            logger.info(f"成功导出对比方案: {file_path}")
            messagebox.showinfo("成功", "对比方案导出成功")

        except Exception as e:
            logger.error(f"导出对比方案失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"导出失败: {str(e)}")

    def _on_toggle_id_field(self):
        """切换ID字段状态"""
        selection = self.fields_tree.selection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个字段")
            return

        item = selection[0]
        values = self.fields_tree.item(item)["values"]
        code = values[1]  # 获取字段代码

        # 切换ID字段状态
        if code in self.id_fields:
            self.id_fields.remove(code)
            self.fields_tree.set(item, "is_id", "")
            logger.info(f"取消ID字段标记: {code}")
        else:
            self.id_fields.append(code)
            self.fields_tree.set(item, "is_id", "✓")
            logger.info(f"设置ID字段标记: {code}")

        logger.info(f"更新ID字段列表: {self.id_fields}")

    def _update_source_mappings_after_field_change(
        self, old_code: str, new_code: str = None
    ):
        """更新数据源映射关系"""
        try:
            # 获取数据源1和数据源2的frame
            source1_frame = self._find_source_frame("数据源1")
            source2_frame = self._find_source_frame("数据源2")

            # 更新数据源1的映射
            if hasattr(source1_frame, "mapping"):
                if new_code:  # 编辑字段
                    source1_frame.mapping = {
                        k: (new_code if v == old_code else v)
                        for k, v in source1_frame.mapping.items()
                    }
                else:  # 删除字段
                    source1_frame.mapping = {
                        k: v for k, v in source1_frame.mapping.items() if v != old_code
                    }

            # 更新数据源2的映射
            if hasattr(source2_frame, "mapping"):
                if new_code:  # 编辑字段
                    source2_frame.mapping = {
                        k: (new_code if v == old_code else v)
                        for k, v in source2_frame.mapping.items()
                    }
                else:  # 删除字段
                    source2_frame.mapping = {
                        k: v for k, v in source2_frame.mapping.items() if v != old_code
                    }

            logger.info(
                f"更新映射关系成功: old_code={old_code}, new_code={new_code if new_code else '(deleted)'}"
            )

        except Exception as e:
            logger.error(f"更新映射关系失败: {str(e)}", exc_info=True)
            raise
